﻿using System;
using System.Linq;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.Workflow;

namespace AdminPack.WorkflowOrganizerReceiver
{
    public class WorkflowOrganizerReceiver : SPItemEventReceiver
    {
        /// <summary>
        /// Current list reference
        /// </summary>
        SPList list;

        /// <summary>
        /// Workflow ID to handle
        /// </summary>
        Guid WorkflowID;

        /// <summary>
        /// Current site URL
        /// </summary>
        String weburl;

        /// <summary>
        /// Current list item reference
        /// </summary>
        SPListItem li;

        /// <summary>
        /// Starts the workflow per the settings for the specified item event.
        /// </summary>
        /// <param name="properties">Item event properties</param>
        void StartWorkflowAnon(SPItemEventProperties properties)
        {
            //elevate permissions so it runs
            SPSecurity.RunWithElevatedPrivileges(delegate()
               {
                   if (properties.ListItem != null)
                   {
                       using (SPSite site = new SPSite(properties.WebUrl))
                       {
                           weburl = properties.WebUrl;
                           using (SPWeb web = site.OpenWeb())
                           {

                               web.AllowUnsafeUpdates = true;

                               //load the list
                               list = web.Lists[properties.ListId];

                               string existing = "";

                               //get the specified workflow order
                               if (list.RootFolder.Properties["WorkflowOrder"] != null)
                                   existing = list.RootFolder.Properties["WorkflowOrder"].ToString();

                               //if workflow order has been specified, process it, otherwise do nothing
                               if (existing != "")
                               {
                                   string[] sets = existing.Split('^');

                                   //the string has Event|Workflow|Delay
                                   var events = from string s in sets
                                                let x = s.Split('|')
                                                where x[0] == properties.EventType.ToString() //get the setting for this event that called the function
                                                select new { WorkflowID = x[1].ToString(), EventName = x[0].ToString(), Delay = x[2].ToString() };

                                   foreach (var o in events)
                                   {
                                       WorkflowID = new Guid(o.WorkflowID);
                                       li = properties.ListItem;

                                       int mili = 0;
                                       int.TryParse(o.Delay, out mili);
                                       mili = mili * 1000;
                                       mili++; //0 is not a valid time so we add 1 mili second
                                       System.Threading.Thread.Sleep(mili); //goto sleep, goto sleep
                                       StartWorkflow();
                                   }
                               }
                               web.AllowUnsafeUpdates = false;
                           }
                       }
                   }
               });
        }

        void StartWorkflow()
        {
            try
            {
                using (SPSite site = new SPSite(weburl))
                {
                    SPWorkflowAssociation assoc = list.WorkflowAssociations[WorkflowID];

                    site.WorkflowManager.StartWorkflow(li, assoc, assoc.AssociationData);
                }
            }
            catch { } //dont want to handle errors here, not sure what to do with this yet
        }

       /// <summary>
       /// An item is being added.
       /// </summary>
       public override void ItemAdding(SPItemEventProperties properties)
       {
           base.ItemAdding(properties);
           StartWorkflowAnon(properties);
       }

       /// <summary>
       /// An item is being updated.
       /// </summary>
       public override void ItemUpdating(SPItemEventProperties properties)
       {
           base.ItemUpdating(properties);
           StartWorkflowAnon(properties);
       }

       /// <summary>
       /// An item is being deleted.
       /// </summary>
       public override void ItemDeleting(SPItemEventProperties properties)
       {
           base.ItemDeleting(properties);
           StartWorkflowAnon(properties);
       }

       /// <summary>
       /// An item is being checked in.
       /// </summary>
       public override void ItemCheckingIn(SPItemEventProperties properties)
       {
           base.ItemCheckingIn(properties);
           StartWorkflowAnon(properties);
       }

       /// <summary>
       /// An item is being checked out.
       /// </summary>
       public override void ItemCheckingOut(SPItemEventProperties properties)
       {
           base.ItemCheckingOut(properties);
           StartWorkflowAnon(properties);
       }

       /// <summary>
       /// An item is being unchecked out.
       /// </summary>
       public override void ItemUncheckingOut(SPItemEventProperties properties)
       {
           base.ItemUncheckingOut(properties);
           StartWorkflowAnon(properties);
       }

       /// <summary>
       /// An attachment is being added to the item.
       /// </summary>
       public override void ItemAttachmentAdding(SPItemEventProperties properties)
       {
           base.ItemAttachmentAdding(properties);
           StartWorkflowAnon(properties);
       }

       /// <summary>
       /// An attachment is being removed from the item.
       /// </summary>
       public override void ItemAttachmentDeleting(SPItemEventProperties properties)
       {
           base.ItemAttachmentDeleting(properties);
           StartWorkflowAnon(properties);
       }

       /// <summary>
       /// A file is being moved.
       /// </summary>
       public override void ItemFileMoving(SPItemEventProperties properties)
       {
           base.ItemFileMoving(properties);
           StartWorkflowAnon(properties);
       }

       /// <summary>
       /// An item was added.
       /// </summary>
       public override void ItemAdded(SPItemEventProperties properties)
       {
           base.ItemAdded(properties);
           StartWorkflowAnon(properties);
       }

       /// <summary>
       /// An item was updated.
       /// </summary>
       public override void ItemUpdated(SPItemEventProperties properties)
       {
           base.ItemUpdated(properties);
           StartWorkflowAnon(properties);
       }

       /// <summary>
       /// An item was deleted.
       /// </summary>
       public override void ItemDeleted(SPItemEventProperties properties)
       {
           base.ItemDeleted(properties);
           StartWorkflowAnon(properties);
       }

       /// <summary>
       /// An item was checked in.
       /// </summary>
       public override void ItemCheckedIn(SPItemEventProperties properties)
       {
           base.ItemCheckedIn(properties);
           StartWorkflowAnon(properties);
       }

       /// <summary>
       /// An item was checked out.
       /// </summary>
       public override void ItemCheckedOut(SPItemEventProperties properties)
       {
           base.ItemCheckedOut(properties);
           StartWorkflowAnon(properties);
       }

       /// <summary>
       /// An item was unchecked out.
       /// </summary>
       public override void ItemUncheckedOut(SPItemEventProperties properties)
       {
           base.ItemUncheckedOut(properties);
           StartWorkflowAnon(properties);
       }

       /// <summary>
       /// An attachment was added to the item.
       /// </summary>
       public override void ItemAttachmentAdded(SPItemEventProperties properties)
       {
           base.ItemAttachmentAdded(properties);
           StartWorkflowAnon(properties);
       }

       /// <summary>
       /// An attachment was removed from the item.
       /// </summary>
       public override void ItemAttachmentDeleted(SPItemEventProperties properties)
       {
           base.ItemAttachmentDeleted(properties);
           StartWorkflowAnon(properties);
       }

       /// <summary>
       /// A file was moved.
       /// </summary>
       public override void ItemFileMoved(SPItemEventProperties properties)
       {
           base.ItemFileMoved(properties);
           StartWorkflowAnon(properties);
       }

       /// <summary>
       /// A file was converted.
       /// </summary>
       public override void ItemFileConverted(SPItemEventProperties properties)
       {
           base.ItemFileConverted(properties);
           StartWorkflowAnon(properties);
       }

       /// <summary>
       /// The list received a context event.
       /// </summary>
       public override void ContextEvent(SPItemEventProperties properties)
       {
           base.ContextEvent(properties);
           StartWorkflowAnon(properties);
       }


    }
}
